package cn.yzj.http;

import org.apache.http.Header;
import org.apache.http.HttpStatus;
import org.apache.http.NameValuePair;
import org.apache.http.client.CookieStore;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.utils.URLEncodedUtils;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.cookie.Cookie;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.BasicCookieStore;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.ssl.SSLContexts;
import org.apache.http.ssl.TrustStrategy;
import org.apache.http.util.EntityUtils;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.select.Elements;

import javax.net.ssl.SSLContext;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

/**
 * 请求类
 *
 * @author gzkemays
 * @since 2020/10/29 19:49
 * @deprecated 代码过于臃肿繁琐，请调用 {@link YzjHttp} 进行请求。对于个体方法已经迁移至 {@link cn.yzj.utils.HttpUtils}
 */
public class MRequest {
  private static CookieStore store;
  public static final String EDGE_USER_AGENT =
      "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36 Edg/91.0.864.64";
  private static RequestConfig config = RequestConfig.custom().setRedirectsEnabled(false).build();
  //    private static CloseableHttpClient httpClient =
  // HttpClients.custom().setConnectionManager(PoolingHttpClient()).build();

  /**
   * 基础设置
   *
   * @return
   */
  public static RequestConfig getRequestConfig() {
    return RequestConfig.custom()
        .setSocketTimeout(20000)
        .setConnectTimeout(20000)
        .setConnectionRequestTimeout(20000)
        .build();
  }
  /**
   * Get 无参请求
   *
   * @param url
   * @return
   */
  public static HttpGet getNoDataGet(String url) {
    HttpGet httpGet = new HttpGet(url);
    httpGet.setConfig(getRequestConfig());
    return httpGet;
  }

  /**
   * Get 有参请求
   *
   * @param map
   * @param url
   * @return
   */
  public static HttpGet getDataGet(String url, Map<Object, Object> map) {
    HttpGet httpGet = new HttpGet(url);
    List<NameValuePair> list = getPairListByMap(map);
    if (list.size() > 0) {
      String param = URLEncodedUtils.format(list, "UTF-8");
      httpGet.setURI(URI.create(url + "?" + param));
    }
    httpGet.setConfig(getRequestConfig());
    return httpGet;
  }

  /**
   * Get 有参请求
   *
   * @param map
   * @param url
   * @return
   */
  public static HttpGet getDataGet(String url, Map<Object, Object> map, String charset) {
    HttpGet httpGet = new HttpGet(url);
    List<NameValuePair> list = getPairListByMap(map);
    if (list.size() > 0) {
      String param = URLEncodedUtils.format(list, charset);
      httpGet.setURI(URI.create(url + "?" + param));
    }
    httpGet.setConfig(getRequestConfig());
    return httpGet;
  }

  /**
   * 无参 Post 请求
   *
   * @param url
   * @return
   */
  public static HttpPost getHttpPost(String url) {
    HttpPost httpPost = new HttpPost(url);
    httpPost.setConfig(getRequestConfig());
    return httpPost;
  }

  /**
   * key value 的表单提交
   *
   * @param url
   * @param map
   * @return
   * @throws UnsupportedEncodingException
   */
  public static HttpPost getUrlEncodedFormPost(String url, Map<Object, Object> map)
      throws UnsupportedEncodingException {
    HttpPost httpPost = new HttpPost(url);
    httpPost.setConfig(getRequestConfig());
    List<NameValuePair> list = getPairListByMap(map);
    if (list.size() > 0) {
      UrlEncodedFormEntity urlEncodedFormEntity = new UrlEncodedFormEntity(list);
      httpPost.setEntity(urlEncodedFormEntity);
    }
    return httpPost;
  }

  /**
   * 正常 String 的 Entity 转换
   *
   * @param url
   * @param data
   * @return
   * @throws UnsupportedEncodingException
   */
  public static HttpPost getStringPost(String url, String data)
      throws UnsupportedEncodingException {
    StringEntity entity = new StringEntity(data);
    HttpPost httpPost = new HttpPost(url);
    httpPost.setConfig(getRequestConfig());
    httpPost.setEntity(entity);
    return httpPost;
  }

  /** Post 获取 Cookie */
  public static String getDataCookieByPost(String url, Map<Object, Object> map) throws Exception {
    HttpPost httpPost = getUrlEncodedFormPost(url, map);
    store = new BasicCookieStore();
    CloseableHttpClient httpClient = HttpClients.custom().setDefaultCookieStore(store).build();
    httpClient.execute(httpPost);
    return getCookie(store);
  }

  /** 无参 Get 获取 Cookie */
  public static String getCookieByGet(String url) throws IOException {
    HttpGet httpGet = getNoDataGet(url);
    store = new BasicCookieStore();
    CloseableHttpClient httpClient = HttpClients.custom().setDefaultCookieStore(store).build();
    httpClient.execute(httpGet);
    return getCookie(store);
  }

  /** 有参 Get 获取 Cookie */
  public static String getDataCookieByGet(String url, Map<Object, Object> map) throws IOException {
    HttpGet httpGet = getDataGet(url, map);
    store = new BasicCookieStore();
    CloseableHttpClient httpClient = HttpClients.custom().setDefaultCookieStore(store).build();
    httpClient.execute(httpGet);
    return getCookie(store);
  }

  /** JSON POST 请求 */
  public static HttpPost getPostJson(String url, String param) {
    StringEntity entity = new StringEntity(param, "utf-8");
    entity.setContentType("application/json");
    //        entity.setContentEncoding("utf-8");
    HttpPost httpPost = new HttpPost(url);
    httpPost.setConfig(getRequestConfig());
    httpPost.setEntity(entity);
    return httpPost;
  }

  /**
   * 通过 map 获取 NameValuePair
   *
   * @param map
   * @return
   */
  public static List<NameValuePair> getPairListByMap(Map<Object, Object> map) {
    Iterator<Map.Entry<Object, Object>> entries = map.entrySet().iterator();
    List<NameValuePair> list = new ArrayList<>();
    while (entries.hasNext()) {
      Map.Entry<Object, Object> entry = entries.next();
      NameValuePair pai =
          new BasicNameValuePair(entry.getKey().toString(), entry.getValue().toString());
      list.add(pai);
    }
    return list;
  }

  /** 获取拼接的 Cookie */
  public static String getCookie(CookieStore store) {
    List<Cookie> cookies = store.getCookies();
    StringBuilder tempcookies = new StringBuilder();
    for (Cookie c : cookies) {
      tempcookies.append(c.getName()).append("=").append(c.getValue()).append(";");
    }
    return tempcookies.toString();
  }

  /** 传入请求获取 String 返回结果 */
  public static String getResultFromRequest(HttpPost httpPost) throws Exception {
    CloseableHttpResponse response;
    CloseableHttpClient httpClient = getIgnoeSSLClient();
    response = httpClient.execute(httpPost);
    return EntityUtils.toString(response.getEntity(), "UTF-8");
  }

  /**
   * 指定返回数据编码
   *
   * @param httpPost
   * @param charset
   * @return
   * @throws Exception
   */
  public static String getResultFromRequest(HttpPost httpPost, String charset) throws Exception {
    CloseableHttpResponse response;
    CloseableHttpClient httpClient = getIgnoeSSLClient();
    response = httpClient.execute(httpPost);
    return EntityUtils.toString(response.getEntity(), charset);
  }
  /** 传入请求获取 String 返回结果 */
  public static String getResultFromRequest(HttpGet httpGet) throws Exception {
    CloseableHttpResponse response;
    CloseableHttpClient httpClient = getIgnoeSSLClient();
    response = httpClient.execute(httpGet);
    return EntityUtils.toString(response.getEntity(), "UTF-8");
  }
  /** 返回数据的编码 */
  public static String getResultFromRequest(HttpGet httpGet, String charset) throws Exception {
    CloseableHttpResponse response;
    CloseableHttpClient httpClient = getIgnoeSSLClient();
    response = httpClient.execute(httpGet);
    return EntityUtils.toString(response.getEntity(), charset);
  }

  /** 获取重定向地址 Get */
  public static String getRedirectLocation(HttpGet httpGet) throws Exception {
    httpGet.setConfig(config);
    CloseableHttpClient httpClient = MRequest.getIgnoeSSLClient();
    CloseableHttpResponse response = httpClient.execute(httpGet);
    int code = response.getStatusLine().getStatusCode();
    String localURI = "none";
    if (code == 302 || code == 301) {
      Header header = response.getFirstHeader("location");
      localURI = header.getValue();
    }
    return localURI;
  }
  /** 获取重定向地址 Post */
  public static String getRedirectLocation(HttpPost httpPost) throws Exception {
    httpPost.setConfig(config);
    CloseableHttpClient httpClient = MRequest.getIgnoeSSLClient();
    CloseableHttpResponse response = httpClient.execute(httpPost);
    int code = response.getStatusLine().getStatusCode();
    String localURI = "none";
    if (code == 302) {
      Header header = response.getFirstHeader("location");
      localURI = header.getValue();
    }
    return localURI;
  }

  /**
   * get 获取 elements
   *
   * @param hg
   * @param charset
   * @return
   * @throws IOException
   */
  public static Elements getElementsWithGet(HttpGet hg, String charset) throws IOException {
    CloseableHttpResponse response;
    CloseableHttpClient httpClient =
        HttpClients.custom().setConnectionManager(PoolingHttpClient()).build();
    Elements elements = null;
    String html;
    response = httpClient.execute(hg);
    if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
      html = EntityUtils.toString(response.getEntity(), charset);
      Document document = Jsoup.parse(html);
      elements = document.getAllElements();
    }
    return elements;
  }

  /**
   * 获取页面 html 信息
   *
   * @param hg
   * @param charset
   * @return
   * @throws IOException
   */
  public static String getHtmlTagWithGet(HttpGet hg, String charset) throws IOException {
    // 创建浏览器
    CloseableHttpClient httpClient =
        HttpClients.custom().setConnectionManager(PoolingHttpClient()).build();
    CloseableHttpResponse response;
    String html = null;
    response = httpClient.execute(hg);
    if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
      html = EntityUtils.toString(response.getEntity(), charset);
    }
    return html;
  }

  /** 在 HtmlTag 基础上返回 document */
  public static Document getDocumentFormTag(HttpGet hg, String charset) throws IOException {
    return Jsoup.parse(getHtmlTagWithGet(hg, charset));
  }

  /**
   * 线程池管理
   *
   * @return
   */
  private static PoolingHttpClientConnectionManager PoolingHttpClient() {
    PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();
    cm.setMaxTotal(200);
    cm.setDefaultMaxPerRoute(50);
    return cm;
  }

  /**
   * 忽略 SSL 证书
   *
   * @return
   * @throws Exception
   */
  public static CloseableHttpClient getIgnoeSSLClient() throws Exception {
    SSLContext sslContext =
        SSLContexts.custom()
            .loadTrustMaterial(
                null,
                new TrustStrategy() {
                  @Override
                  public boolean isTrusted(X509Certificate[] x509Certificates, String s)
                      throws CertificateException {
                    return true;
                  }
                })
            .build();
    // 创建httpClient
    CloseableHttpClient client =
        HttpClients.custom()
            .setSSLContext(sslContext)
            .setSSLHostnameVerifier(new NoopHostnameVerifier())
            .build();
    return client;
  }
}
